The brythonmagic extension has been tested on:
import IPython
IPython.version_info
Just type the following:
%install_ext https://raw.github.com/kikocorreoso/brythonmagic/master/brythonmagic.py
%load_ext brythonmagic
And load the brython js lib in the notebook:
%%HTML
<script type="text/javascript" src="http://brython.info/src/brython_dist.js"></script>
In order to load javascript libraries in a safety way you should try to use https instead of http when possible (read more here). If you don't trust the source and/or the source cannot be loaded using https then you could download the javascript library and load it from a local location.
The brythonmagic provides you a cell magic, %%brython
, to run brython code and show the results in a html div
tag below the code cell.
You can use several options:
div
container in case you want to 'play' with it in other cell. If you don't define an output the div
will have and id
with the following format 'brython-container-[random number between 0 and 999999]'-S, --scripts: Use this option to run code previously defined in other Brython code cells. The values should be the provided values in the -s/--script option in other Brython code cells.
-f, --fiddle: With this option, the code in the cell will be automatically uploaded to gist.github.com/ as an anonymous gist with several files in it. This files will be used to create an anonymous 'fiddle' on jsfiddle.net. Finally, some links will be printed in the output linking to the gist and the fiddle. See an example here (https://gist.github.com/anonymous/b664e8b4617afc09db6c and http://jsfiddle.net/gh/gist/library/pure/b664e8b4617afc09db6c/)
-e, --embedfiddle: With this option, the code in the cell will be automatically uploaded to gist.github.com/ as an anonymous gist with several files in it. This files will be used to create an anonymous 'fiddle' on jsfiddle.net. Finally, some links will be printed in the output linking to the gist and the fiddle and an iframe will be created showing the fiddle on jsfiddle.net.
[WARNING] This options may change as the brythonmagic is in active development.
-p, --print
option¶The following example shows the use of the -p
, --print
option.
[HINT] The result of the print is shown in the javascript console of your browser.
%%brython -p
print('hello world!')
-c, --container
option¶In the following example can be seen the use of the -c
, --container
. The -p
is also used to show you the result. See the id
attribute of the div
tag created:
%%brython -c my_container -p
from browser import doc, html
# This will be printed in the js console of your browser
print('Hello world!')
# This will be printed in the container div on the output below
doc["my_container"] <= html.P("This text is inside the div",
style = {"backgroundColor": "cyan"})
-i, --input
option¶In this example you can see how the data are passed to brython from python using the -i
or --input
option. First, we create some data in a regular Python cell.
data_list = [1,2,3,4]
data_tuple = (1,2,3,4)
data_dict = {'one': 1, 'two': 2}
data_str = """
Hello
GoodBye
"""
# A numpy array can be converted to a list and you will obtain a brython list
import numpy as np
data_arr = np.empty((3,2))
data_arr = data_arr.tolist()
And now, the created data are passed to Brython and used in the Brython code cell. Remember that only Python lists, tuples, dicts and strings are allowed as inputs.
%%brython -c p2b_data_example -i data_list data_tuple data_dict data_str data_arr
from browser import doc, html
doc["p2b_data_example"] <= html.P(str(data_list))
doc["p2b_data_example"] <= html.P(str(type(data_list)))
doc["p2b_data_example"] <= html.P(str(data_tuple))
doc["p2b_data_example"] <= html.P(str(type(data_tuple)))
doc["p2b_data_example"] <= html.P(str(data_dict))
doc["p2b_data_example"] <= html.P(str(type(data_dict)))
doc["p2b_data_example"] <= html.P(data_str.replace('Hello', 'Hi'))
doc["p2b_data_example"] <= html.P(str(type(data_str)))
doc["p2b_data_example"] <= html.P(str(data_arr))
doc["p2b_data_example"] <= html.P(str(type(data_arr)))
-h, --html
option¶In this example you can see how to create some HTML code in a cell and then use that HTML code in the brython cell. In this way you do not need to create the HTML code via scripting with Brython.
html = """
<div id="paragraph">Hi</div>
"""
%%brython -c html_ex -h html
from browser import doc
doc["paragraph"].style = {"color": "yellow",
"fontSize": "100px",
"lineHeight": "150px",
"textAlign": "center",
"backgroundColor": "black"}
-s, --script
option¶With this option you are creating a reference of the code in the Brython cell (e.g., an id
of the HTML script
tag created to run the Brython code). So, if you need to use the code of the Brython cell in a future Brython cell you could reference it by its id
. Let's see this on an example (the -p
option is used to show you the generated code and how the id
of the script
tag is created):
%%brython -s my_dummy_function -p
def dummy_function(some_text):
print(some_text)
-S, --scripts
option¶This option could be used to call code created in a previous Brython code cell using its id
(see the -s
option above). In the following code cell we will use the dummy_function
created in another Brython code cell. The dummy_function
was created in a script
tag with an id="my_dummy_function"
.
[HINT] The result of the Brython code cell below is shown in the javascript console of your browser.
%%brython -S my_dummy_function
dummy_function('Hi')
-f, --fiddle
option¶With this option, the code in the cell will be automatically uploaded to gist.github.com/ as an anonymous gist with several files in it. This files will be used to create an anonymous 'fiddle' on jsfiddle.net. Finally, some links will be printed in the output linking to the gist and the fiddle.
%%brython -f
from browser import alert
alert('hello world from jsfiddle!')
-e, --embedfiddle
option¶With this option, the code in the cell will be automatically uploaded to gist.github.com/ as an anonymous gist with several files in it. This files will be used to create an anonymous 'fiddle' on jsfiddle.net. Finally, some links will be printed in the output linking to the gist and the fiddle and an iframe will be created showing the fiddle on jsfiddle.net.
%%brython -e
from browser import alert
alert('hello world from jsfiddle!')
First step should be to learn the brython documentation. You can find the docs here:
http://brython.info/doc/en/index.html?lang=en
In the following section I will show you some dummy examples.
In this example let's see how to pop up an alert window. This could be an standard 'Hello world!' example in the Brython world.
%%brython
from browser import alert
alert('Hello world!, Welcome to the brythonmagic!')
div
container¶In this example we just write inside a <div>
ten numbers using a <P>
tag for each number.
[HINT] To see the line numbers in the code cell just go to the cell and press <CTRL>-m
and then l
.
P
tag and write the value of i
inside. Finally, add the P
element to the selected div
, in this case the div
with "simple_example" id
attribute.%%brython -c simple_example
from browser import doc, html
for i in range(10):
doc["simple_example"] <= html.P(i)
In the following cell we create a multiplication table. First, we create a table
tag. We append the table rows and cells (TR
and TD
tags) and, finally, we append the final table to the div
with "table" id
attribute.
%%brython -c table
from browser import doc, html
table = html.TABLE()
for i in range(10):
color = ['cyan','#dddddd'] * 5
table <= html.TR(
html.TD(str(i+1) + ' x 2 =', style = {'backgroundColor':color[i]}) +
html.TD((i+1)*2, style = {'backgroundColor':color[i]}))
doc['table'] <= table
In the following example we draw a shape using the HTML5 canvas
. Also, we add some controls to stop and animate the shape. The example has been adapted from the javascript example available here.
%%brython -c canvas_example
from browser.timer import request_animation_frame as raf
from browser.timer import cancel_animation_frame as caf
from browser import doc, html
from time import time
import math
# First we create a table to insert the elements
table = html.TABLE(cellpadding = 10)
btn_anim = html.BUTTON('Animate', Id="btn-anim", type="button")
btn_stop = html.BUTTON('Stop', Id="btn-stop", type="button")
cnvs = html.CANVAS(Id="raf-canvas", width=256, height=256)
table <= html.TR(html.TD(btn_anim + btn_stop) +
html.TD(cnvs))
doc['canvas_example'] <= table
# Now we access the canvas context
ctx = doc['raf-canvas'].getContext( '2d' )
# And we create several functions in charge to animate and stop the draw animation
toggle = True
def draw():
t = time() * 3
x = math.sin(t) * 96 + 128
y = math.cos(t * 0.9) * 96 + 128
global toggle
if toggle:
toggle = False
else:
toggle = True
ctx.fillStyle = 'rgb(200,200,20)' if toggle else 'rgb(20,20,200)'
ctx.beginPath()
ctx.arc( x, y, 6, 0, math.pi * 2, True)
ctx.closePath()
ctx.fill()
def animate(i):
global id
id = raf(animate)
draw()
def stop(i):
global id
print(id)
caf(id)
doc["btn-anim"].bind("click", animate)
doc["btn-stop"].bind("click", stop)
In Brython there is a javascript library that allows to access objects available in the javascript namespace. In this example we are using a javascript object (D3.js library) from Brython.
So, in order to allow Brython to access to D3 first you should load the D3 library.
%%HTML
<script type="text/javascript" src="http://d3js.org/d3.v2.js"></script>
Now, we can access D3 objects using JSObject
(see example below).
%%brython -c simple_d3
from browser import window, document, html
from javascript import JSObject
d3 = window.d3
container = JSObject(d3.select("#simple_d3"))
svg = container.append("svg").attr("width", 100).attr("height", 100)
circle1 = svg.append("circle").style("stroke", "gray").style("fill", "gray").attr("r", 40)
circle1.attr("cx", 50).attr("cy", 50).attr("id", "mycircle")
circle2 = svg.append("circle").style("stroke", "gray").style("fill", "white").attr("r", 20)
circle2.attr("cx", 50).attr("cy", 50)
def over(ev):
document["mycircle"].style.fill = "blue"
def out(ev):
document["mycircle"].style.fill = "gray"
document["mycircle"].bind("mouseover", over)
document["mycircle"].bind("mouseout", out)
An example to hide or show the code cells using a button.
%%brython -c manipulating
from browser import document, html
def hide(ev):
divs = document.get(selector = 'div.input')
for div in divs:
div.style.display = "none"
def show(ev):
divs = document.get(selector = 'div.input')
for div in divs:
div.style.display = "inherit"
document["manipulating"] <= html.BUTTON('Hide code cells', Id="btn-hide")
document["btn-hide"].bind("click", hide)
document["manipulating"] <= html.BUTTON('Show code cells', Id="btn-show")
document["btn-show"].bind("click", show)
A more complete D3 example. In this case, first we create some data in Python.
from random import randint
n = 100
x = [randint(0,800) for i in range(n)]
y = [randint(0,600) for i in range(n)]
r = [randint(25,50) for i in range(n)]
red = [randint(0,255) for i in range(n)]
green = [randint(0,255) for i in range(n)]
blue = [randint(0,255) for i in range(n)]
And now, the data is passed to Brython to be used in a D3 plot. In this case, the D3.js library is already loaded so it is not necessary to load it.
%%brython -c other_d3 -i x y r red green blue
from browser import window, document, html
from javascript import JSObject
d3 = window.d3
WIDTH = 800
HEIGHT = 600
container = JSObject(d3.select("#other_d3"))
svg = container.append("svg").attr("width", WIDTH).attr("height", HEIGHT)
class AddShapes:
def __init__(self, x, y, r, red, green, blue, shape = "circle", interactive = True):
self.shape = shape
self.interactive = interactive
self._color = "gray"
self.add(x, y, r, red, green, blue)
def over(self, ev):
self._color = ev.target.style.fill
document[ev.target.id].style.fill = "white"
def out(self, ev):
document[ev.target.id].style.fill = self._color
def add(self, x, y, r, red, green, blue):
for i in range(len(x)):
self.idx = self.shape + '_' + str(i)
self._color = "rgb(%s,%s,%s)" % (red[i], green[i], blue[i])
shaped = svg.append(self.shape).style("stroke", "gray").style("fill", self._color).attr("r", r[i])
shaped.attr("cx", x[i]).attr("cy", y[i]).attr("id", self.idx)
if self.interactive:
doc[self.idx].bind("mouseover", self.over)
doc[self.idx].bind("mouseout", self.out)
plot = AddShapes(x, y, r, red, green, blue, interactive = True)
In the following example we will use OpenLayers to center a map in a specific location, with a zoom and a projection and then we will draw some vector points around the location.
As before, first we should load the OpenLayers.js library.
%%HTML
<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script>
And now we can create a map using JSConstructor
available in the built-in Brython javascript library
%%brython -c ol_map
from browser import document, window
from javascript import JSConstructor, JSObject
## Div layout
document['ol_map'].style.width = "800px"
document['ol_map'].style.height = "400px"
document['ol_map'].style.border = "1px solid black"
OpenLayers = window.OpenLayers
## Map
_map = JSConstructor(OpenLayers.Map)('ol_map')
## Addition of a OpenStreetMap layer
_layer = JSConstructor(OpenLayers.Layer.OSM)( 'Simple OSM map')
_map.addLayer(_layer)
## Map centered on Lon, Lat = (-3.671416, 40.435897) and a zoom = 14
## with a projection = "EPSG:4326" (Lat-Lon WGS84)
_proj = JSConstructor(OpenLayers.Projection)("EPSG:4326")
_center = JSConstructor(OpenLayers.LonLat)(-3.671416, 40.435897)
_center.transform(_proj, _map.getProjectionObject())
_map.setCenter(_center, 10)
## Addition of some points around the defined location
lons = [-3.670, -3.671, -3.672, -3.672, -3.672,
-3.671, -3.670, -3.670]
lats = [40.435, 40.435, 40.435, 40.436, 40.437,
40.437, 40.437, 40.436]
site_points = []
site_style = {}
points_layer = JSConstructor(OpenLayers.Layer.Vector)("Point Layer")
_map.addLayer(points_layer)
for lon, lat in zip(lons, lats):
point = JSConstructor(OpenLayers.Geometry.Point)(lon, lat)
point.transform(_proj, _map.getProjectionObject())
_feat = JSConstructor(OpenLayers.Feature.Vector)(point)
points_layer.addFeatures(_feat)
A dummy example using raphaƫl.js library.
As usual, first we should include the library:
%%javascript
require([ "http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.2/raphael-min.js" ], function (Raphael) {
console.log(Raphael);
});
And now let's make a dumb example using JSObject
.
%%brython -c raphael_ex
from browser import window
from javascript import JSObject
Raphael = window.Raphael
paper = JSObject(Raphael("raphael_ex", 400, 400))
#Draw rectagle
rect = paper.rect(1,1,398,398)
rect.attr("stroke", "black")
#Draw orbits
for rot in range(90,280,60):
ellipse = paper.ellipse(200, 200, 180, 50)
ellipse.attr("stroke", "gray")
ellipse.rotate(rot)
#Draw nucleus
nucleus = paper.circle(200,200,40)
nucleus.attr("fill", "black")
# Draw electrons
electron = paper.circle(200, 20, 10)
electron.attr("fill", "red")
electron = paper.circle(44, 290, 10)
electron.attr("fill", "yellow")
electron = paper.circle(356, 290, 10)
electron.attr("fill", "blue")
The cells starts by 0 and all the cells (markdown, headings, code,...) has a number. If we want to re-run some cells in a programmatically way it is useful to know the number of the cells to identify them. You can delete the cell numbers using show_cell_number(on = False)
:
%%brython
from browser import doc, html
def show_cell_number(on = True):
cells = doc.get(selector = '.input_prompt')
for i, cell in enumerate(cells):
if on:
if 'In' in cell.html and '<br>' not in cell.html:
cell.html += "<br>cell #" + str(i)
else:
if 'In' in cell.text:
cell.html = cell.html.split('<br>')[0]
show_cell_number(on = True)
Imagine you have several cells of code and you want just to modify some data and run again these cells as a loop not having to create a big cell with the code of the cells together.
%%brython
from javascript import JSObject
from browser import window
IPython = window.IPython
nb = IPython.notebook
# This is used to prevent an infinite loop
this_cell = nb.get_selected_index()
for i in range(1,10): # Ths will run cells 1 to 9 (the beginning of the nb)
cell = nb.get_cell(i)
if cell.cell_type == "code" and i != this_cell:
cell.execute()
If you want to compile all the code used in a notebook you can use this recipe (use crtl + Enter
to run the cell if you don't want a bad behaviour):
%%brython
from javascript import JSObject
from browser import window
IPython = window.IPython
nb = IPython.notebook
this_cell = nb.get_selected_index()
total_cells = nb.ncells()
code = ""
first_cell = True
for i in range(total_cells):
cell = nb.get_cell(i)
if cell.cell_type == "code" and i != this_cell:
if first_cell:
code += "# This cell has been generated automatically using a brython script\n\n"
code += "# code from cell " + str(i) + '\n'
first_cell = False
else:
code += "\n\n\n# code from cell " + str(i) + '\n'
code += cell.get_text() + '\n'
nb.insert_cell_below('code')
new_cell = nb.get_cell(this_cell + 1)
new_cell.set_text(code)
Lets modify a little bit the look of the notebook. Warning: The result will be very ugly...
%%brython -s styling
from browser import doc, html
# Changing the background color
body = doc[html.BODY][0]
body.style = {"backgroundColor": "#99EEFF"}
# Changing the color of the imput prompt
inps = body.get(selector = ".input_prompt")
for inp in inps:
inp.style = {"color": "blue"}
# Changin the color of the output cells
outs = body.get(selector = ".output_wrapper")
for out in outs:
out.style = {"backgroundColor": "#E0E0E0"}
# Changing the font of the text cells
text_cells = body.get(selector = ".text_cell")
for cell in text_cells:
cell.style = {"fontFamily": """"Courier New", Courier, monospace""",
"fontSize": "20px"}
# Changing the color of the code cells.
code_cells = body.get(selector = ".CodeMirror")
for cell in code_cells:
cell.style = {"backgroundColor": "#D0D0D0"}